﻿using SCG.General;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//represents a dungeon room

namespace TTEngine
{
    public abstract class Room
    {
        //create an instance of the same type of room
        public abstract Room Clone();

        //public properties
        public DungeonLevel Level { get; set; }
        public int X { get; set; }
        public int Y { get; set; }
        public bool UseConnectorPoints { get; set; }
        public int StartConnector { get; set; }
        public int EndConnector { get; set; }
        public int Twists { get; set; }

        public int DifficultyLevel
        {
            get
            {
                return 1;
            }
        }

        //a list of tags that represent which factions can build this room
        public List<string> FactionTags
        {
            get
            {
                return _factionTags;
            }
        }

        //Faction holder
        public Faction Faction { get; set; }

        public virtual bool IsEntrance
        {
            get
            {
                return false;
            }
        }

        public virtual bool IsCorridor
        {
            get
            {
                return false;
            }
        }

        public CharMatrix Matrix
        {
            get
            {
                return _matrix;
            }
            set
            {
                _matrix = value;
            }
        }

        //locations
        public int Left
        {
            get
            {
                return X;
            }
        }
        public int Right
        {
            get
            {
                return X + _matrix.Width - 1;
            }
        }
        public int Top
        {
            get
            {
                return Y;
            }
        }
        public int Bottom
        {
            get
            {
                return Y + _matrix.Height - 1;
            }
        }

        //get dimensions
        public int Width
        {
            get
            {
                return _matrix.Width;
            }
        }
        public int Height
        {
            get
            {
                return _matrix.Height;
            }
        }

        //get center
        public int CenterX
        {
            get
            {
                return Width / 2 + X;
            }
        }
        public int CenterY
        {
            get
            {
                return Height / 2 + Y;
            }
        }
        public SCGPoint Center
        {
            get
            {
                return new SCGPoint(CenterX, CenterY);
            }
        }

        //get the room bounding rectangle
        SCGRect Rect
        {
            get
            {
                return new SCGRect(X, Y, Width, Height);
            }
        }

        //flipped connector points
        public int StartConnectorFlipped
        {
            get
            {
                return Width - StartConnector - 1;
            }
        }
        public int StartConnectorFlippedByHeight
        {
            get
            {
                return Height - StartConnector - 1;
            }
        }

        //does this room touch another room? 
        //test each square of base room against all surrounding squares of target room
        public bool Touches(Room room)
        {
            int xOff = room.X - X;
            int yOff = room.Y - Y;
            for(int y = 0; y < Height; y++)
                for(int x = 0; x < Width; x++)
                    if (Matrix.Get(x, y) == Globals.TERRAIN_FLOOR)
                    {
                        
                        for(int y2 = -1; y2 <= 1; y2++)
                            for (int x2 = -1; x2 <= 1; x2++)
                                if (y2 == 0 || x2 == 0)
                                {
                                    int tx = x - xOff + x2;
                                    int ty = y - yOff + y2;
                                    if (room.Matrix.InBounds(tx, ty))
                                        if (room.Matrix.Get(tx, ty) == Globals.TERRAIN_FLOOR)
                                            return true;
                                }
                    }
            return false;
        }

        //twist the room
        public void Twist()
        {
            _matrix = _matrix.Twist();
            Twists++;
            if (Twists == 4)
                Twists = 0;
        }
        public void Twist(int times)
        {
            while (times > 0)
            {
                Twist();
                times--;
            }
        }

        //get a random floor point
        public SCGPoint GetRandomFloorPoint()
        {
            SCGPoint pt = new SCGPoint();
            char c = Globals.TERRAIN_WALL;
            while (c == Globals.TERRAIN_WALL)
            {
                pt.X = Globals.RandomIntFromTo(0, Width - 1);
                pt.Y = Globals.RandomIntFromTo(0, Height - 1);
                c = Matrix.Get(pt.X, pt.Y);
            }
            pt.Offset(X, Y);
            return pt;
        }

        //post-processing for build process
        public virtual void PostProcessing()
        {
        }

        //carve out a section
        public void Carve(int x, int y, int length, int repeat)
        {
            while (repeat > 0)
            {
                int cells = length;
                int cx = x;
                int cy = y;
                while (cells > 0)
                {
                    Matrix.SetSafely(cx, cy, Globals.TERRAIN_FLOOR);
                    SCGDirection dir = DirectionUtils.RandomDirection;
                    dir.Advance(ref cx, ref cy);
                    cells--;
                }
                repeat--;
            }
        }

        //per-impulse processing
        public virtual void ProcessImpulse()
        {
        }

        //private members
        private CharMatrix _matrix;
        private List<string> _factionTags = new List<string>();
    }
}
